package com.xinqi.modules.prepare.video.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xinqi.common.base.dto.QuestionBaseDTO;
import com.xinqi.common.base.dto.utils.QuestionStats;
import com.xinqi.common.base.enums.YesNoNumberEnum;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.response.PageInfo;
import com.xinqi.common.base.response.Param;
import com.xinqi.common.base.utils.lambda.Lambdas;
import com.xinqi.common.core.utils.StringUtils;
import com.xinqi.common.mybatis.utils.Pages;
import com.xinqi.common.mybatis.utils.Queries;
import com.xinqi.modules.prepare.common.dto.data.PrepareVideoData;
import com.xinqi.modules.prepare.common.enums.PrepareLimitEnum;
import com.xinqi.modules.prepare.common.service.PrepareAuthService;
import com.xinqi.modules.prepare.common.utils.QuestionUtils;
import com.xinqi.modules.prepare.folder.manager.PrepareFileFolderManager;
import com.xinqi.modules.prepare.prepare.enums.PrepareMemberPermissionEnum;
import com.xinqi.modules.prepare.video.convert.PrepareVideoPointConvert;
import com.xinqi.modules.prepare.video.domain.PrepareVideoPointEntity;
import com.xinqi.modules.prepare.video.dto.req.PrepareVideoPointCreateDTO;
import com.xinqi.modules.prepare.video.dto.req.PrepareVideoPointDeleteDTO;
import com.xinqi.modules.prepare.video.dto.req.PrepareVideoPointQueryDTO;
import com.xinqi.modules.prepare.video.dto.req.PrepareVideoPointUpdateDTO;
import com.xinqi.modules.prepare.video.dto.rsp.PrepareVideoPointResultDTO;
import com.xinqi.modules.prepare.video.manager.PrepareVideoPointManager;
import com.xinqi.modules.prepare.video.service.PrepareVideoPointService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 备课区互动视频环节服务层实现
 *
 * @author: system
 * @date: 2023/03/19
 */
@Validated
@Service("prepareVideoPointService")
@RequiredArgsConstructor
public class PrepareVideoPointServiceImpl implements PrepareVideoPointService {
    private final PrepareVideoPointConvert prepareVideoPointConvert;
    private final PrepareVideoPointManager prepareVideoPointManager;
    private final PrepareFileFolderManager prepareFileFolderManager;
    private final PrepareAuthService prepareAuthService;

    /**
     * 分页查询 备课区互动视频环节数据
     */
    @Override
    @DS("slaver")
    public PageInfo<PrepareVideoPointResultDTO> page(Param pageable, PrepareVideoPointQueryDTO query) {
        IPage<PrepareVideoPointEntity> page = prepareVideoPointManager.page(Pages.page(pageable), wrapper(query));
        return Pages.convert(page, prepareVideoPointConvert::convert);
    }

    /**
     * 查询 备课区互动视频环节数据
     */
    @Override
    public List<PrepareVideoPointResultDTO> find(PrepareVideoPointQueryDTO query) {
        List<PrepareVideoPointResultDTO> list = prepareVideoPointManager.list(wrapper(query)).stream()
            .map(prepareVideoPointConvert::convert).collect(Collectors.toList());
        // 校验试题是否有 答案 没有动态获取答案
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach(item -> {
                if (CollectionUtils.isNotEmpty(item.getQuestionContent())) {
                    item.getQuestionContent().forEach(question -> {
                        if (StringUtils.isEmpty(question.getAnswer())) {
                            final String[] answer = {""};
                            question.getOptionList().forEach(option -> {
                                if (Objects.equals(YesNoNumberEnum.YES.getCode(), option.getSelected())) {
                                    if (StringUtils.isEmpty(answer[0])) {
                                        answer[0] = option.getId();
                                    } else {
                                        answer[0] = answer[0] + "," + option.getId();
                                    }
                                }
                            });
                            question.setAnswer(answer[0]);
                        }
                    });
                }
            });
        }
        return list;
    }

    private LambdaQueryWrapper<PrepareVideoPointEntity> wrapper(PrepareVideoPointQueryDTO query) {
        LambdaQueryWrapper<PrepareVideoPointEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(PrepareVideoPointEntity::getId, v));
        Queries.accept(query.getVideoId(), v -> wrapper.eq(PrepareVideoPointEntity::getVideoId, v));
        return wrapper;
    }

    /**
     * 根据id查询 备课区互动视频环节数据
     */
    @Override
    public PrepareVideoPointResultDTO findById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return Optional.ofNullable(prepareVideoPointManager.findById(id)).map(prepareVideoPointConvert::convert).orElse(null);
    }

    /**
     * 新增 备课区互动视频环节数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long insert(@Valid PrepareVideoPointCreateDTO dto) {
        Long videoId = dto.getVideoId();
        LambdaQueryWrapper<PrepareVideoPointEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PrepareVideoPointEntity::getVideoId, videoId);
        PrepareLimitEnum.互动视频帧限制.check(prepareVideoPointManager.count(wrapper) + 1);
        prepareAuthService.check(dto.getPrepareId(), PrepareMemberPermissionEnum.新建);
        PrepareVideoPointEntity entity = prepareVideoPointConvert.create(dto);
        // 处理题目汇总信息
        questionProcess(dto.getQuestionContent(), entity);
        prepareVideoPointManager.save(entity);
        return entity.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insert(Long prepareId, Long videoId, List<PrepareVideoData.PrepareVideoPointData> pointList) {
        if (CollectionUtils.isEmpty(pointList)) {
            return;
        }
        for (PrepareVideoData.PrepareVideoPointData data : pointList) {
            PrepareVideoPointCreateDTO dto = prepareVideoPointConvert.create(data);
            dto.setPrepareId(prepareId);
            dto.setVideoId(videoId);
            insert(dto);
        }
    }

    private static void questionProcess(List<QuestionBaseDTO> dto, PrepareVideoPointEntity entity) {
        // 处理题目汇总信息
        QuestionStats status = QuestionUtils.status(dto);
        entity.setQuestionTotal(status.getQuestionTotal());
        entity.setQuestionTypeTotal(status.getQuestionTypeTotal());
        entity.setTotalScore(status.getTotalScore());
        // 限制题目数量
        PrepareLimitEnum.互动视频帧题目限制.check(() -> Lambdas.size(dto));
    }

    /**
     * 根据id修改 备课区互动视频环节数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateById(@Valid PrepareVideoPointUpdateDTO dto) {
        PrepareVideoPointEntity old = Optional.ofNullable(prepareVideoPointManager.getById(dto.getId()))
            .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("数据不存在"));
        prepareAuthService.check(old.getPrepareId(), PrepareMemberPermissionEnum.编辑);
        PrepareVideoPointEntity entity = prepareVideoPointConvert.update(dto);
        // 处理题目汇总信息
        questionProcess(dto.getQuestionContent(), entity);
        return prepareVideoPointManager.updateById(entity);
    }

    /**
     * 根据id删除 备课区互动视频环节数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        PrepareVideoPointEntity entity = Optional.ofNullable(prepareVideoPointManager.getById(id))
            .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("数据不存在"));
        prepareAuthService.check(entity.getPrepareId(), PrepareMemberPermissionEnum.删除);
        return prepareVideoPointManager.removeById(id);
    }

    /**
     * 根据id删除 备课区互动视频环节数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(PrepareVideoPointDeleteDTO dto) {
        return deleteById(dto.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteByVideoId(Long videoId) {
        return prepareVideoPointManager.deleteByVideoId(videoId);
    }

}
